//============================================================================
//File    : clock12_glass_lcd.c                                              =
//Date    : 2015.03.02                                                       =
//Author  : zty                                                              =
//Diary   :                                                                  =
//============================================================================

/* Includes ------------------------------------------------------------------*/
#include "clock12_glass_lcd.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
  @verbatim
================================================================================
                              GLASS LCD MAPPING
================================================================================
						
           ----A----
          |         |
          F         B
          |         |
          |----G----|
          |         |
          E         C
          |         |
				P. ----D---- 
           

A LCD character coding is based on the following matrix:

     COM0 COM1 COM2 COM3
SEG0{ A  , F  , E  , P1 }
SEG1{ B  , G  , C  , D  }
 ~  { *  , *  , *  , *  }
 ~  { *  , *  , *  , *  }

The character 3 for example is:
-------------------------------
    { 1 , 0 , 0 , 0 }
    { 1 , 1 , 1 , 1 }
    { 0 , 0 , 0 , 0 }
    { 0 , 0 , 0 , 0 }
   -------------------
   =  3   2   2   2   hex

   => '3' = 0x3222

  @endverbatim
  */

/**
  * @brief LETTERS AND NUMBERS MAPPING DEFINITION
  */

CONST uint16_t mask[4] =
  {
    0xF000, 0x0F00, 0x00F0, 0x000F
  };
CONST uint8_t shift[4] =
  {
    12, 8, 4, 0
  };

/* Digit frame buffer */
uint8_t digit[4];

/* Letters and number map of PD_878 LCD */
CONST uint16_t LetterMap[26] =
  {
    /* A      B      C      D      E      F      G      H      I  */
    0x4D70, 0x6469, 0x0212, 0x6449, 0x4911, 0x4910, 0x4171, 0x0D70, 0x6009,
    /* J      K      L      M      N      O      P      Q      R  */
    0x0451, 0x0B12, 0x0111, 0x8750, 0x8552, 0x4551, 0x4D30, 0x4553, 0x4D32,
    /* S      T      U      V      W      X      Y      Z  */
    0x4961, 0x6008, 0x0551, 0x0390, 0x05D2, 0x8282, 0x8208, 0x4281
  };

CONST uint16_t NumberMap[10] =
  {
    /*   0       1       2       3       4       5       6       7       8       9  */
    0x3132, 0x2020, 0x3212, 0x3222, 0x2320, 0x1322, 0x1332, 0x3020, 0x3332, 0x3322
  };

/* Private function prototypes -----------------------------------------------*/
static void Convert(uint8_t* c, Point_Typedef point, Apostrophe_Typedef apostrophe);

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Configures the LCD GLASS relative GPIO port IOs and LCD peripheral.
  * @param  None
  * @retval None
  */
void LCD_GLASS_Init(void)
{
  /*
    The LCD is configured as follow:
     - clock source = LSE (32.768 KHz)
     - Voltage source = Internal
     - Prescaler = 2
     - Divider = 18 (16 + 2)  
     - Mode = 1/4 Duty, 1/3 Bias
     - LCD frequency = (clock source * Duty) / (Prescaler * Divider)
                     = 228 Hz ==> Frame frequency = 57 Hz */
										 
    /* Enable LCD clock */
    CLK_PeripheralClockConfig(CLK_Peripheral_LCD, ENABLE);
   
    /* Initialize the LCD */
    LCD_Init(LCD_Prescaler_2, LCD_Divider_31, LCD_Duty_1_4,
             LCD_Bias_1_3, LCD_VoltageSource_Internal);
   
    /* Mask register */
	  /* in the Board I use 8 to 15 segments. */
    //LCD_PortMaskConfig(LCD_PortMaskRegister_0, 0xFF);
    LCD_PortMaskConfig(LCD_PortMaskRegister_1, 0xFF);
    //LCD_PortMaskConfig(LCD_PortMaskRegister_2, 0xFF);
    //LCD_PortMaskConfig(LCD_PortMaskRegister_3, 0xFF);
   
    /* To set contrast to mean value */
    LCD_ContrastConfig(LCD_Contrast_3V0);
    LCD_DeadTimeConfig(LCD_DeadTime_0);
    LCD_PulseOnDurationConfig(LCD_PulseOnDuration_1);
    
	  /* Enable LCD peripheral */
    LCD_Cmd(ENABLE);
}

/**
  * @brief  This function writes a char in the LCD frame buffer.
  * @param  ch: the character to dispaly.
  * @param  point: a point to add in front of char
  *         This parameter can be: POINT_OFF or POINT_ON
  * @param  apostrophe: flag indicating if a apostrophe has to be add in front
  *         of displayed character.
  *         This parameter can be: APOSTROPHE_OFF or APOSTROPHE_ON.
  * @param  position: position in the LCD of the caracter to write [0:7]
  * @retval None
  * @par    Required preconditions: The LCD should be cleared before to start the
  *         write operation.
  */
void LCD_GLASS_WriteChar(uint8_t* ch, Point_Typedef point,
                         Apostrophe_Typedef apostrophe, uint8_t position)
{
  Convert(ch, point, apostrophe);

  switch (position)
  {
      /* Position 0 on LCD (Digit1)*/
    case 0:
      LCD->RAM[LCD_RAMRegister_1] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_1] |= (uint8_t)(digit[0] & 0x03);// 1A 1B
			
      LCD->RAM[LCD_RAMRegister_4] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_4] |= (uint8_t)((digit[1]<<4) & 0x30);// 1F 1G
			
      LCD->RAM[LCD_RAMRegister_8] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_8] |= (uint8_t)(digit[2] & 0x03);// 1E 1C
			
      LCD->RAM[LCD_RAMRegister_11] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_11] |= (uint8_t)((digit[3]<<4) & 0x30);// 1P1 1D
			
      break;
     
      /* Position 1 on LCD (Digit2)*/
    case 1:
			LCD->RAM[LCD_RAMRegister_1] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_1] |= (uint8_t)((digit[0]<<2) & 0x0C);// 2A 2B
			
      LCD->RAM[LCD_RAMRegister_4] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_4] |= (uint8_t)((digit[1]<<6) & 0xC0);// 2F 2G
			
      LCD->RAM[LCD_RAMRegister_8] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_8] |= (uint8_t)((digit[2]<<2) & 0x0C);// 2E 2C
			
      LCD->RAM[LCD_RAMRegister_11] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_11] |= (uint8_t)((digit[3]<<6) & 0xC0);// 2P1 2D
			
      break;
     
      /* Position 2 on LCD (Digit3)*/
    case 2:
      LCD->RAM[LCD_RAMRegister_1] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_1] |= (uint8_t)((digit[0]<<4) & 0x30);// 3A 3B
			
      LCD->RAM[LCD_RAMRegister_5] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_5] |= (uint8_t)(digit[1] & 0x03);// 3F 3G
			
      LCD->RAM[LCD_RAMRegister_8] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_8] |= (uint8_t)((digit[2]<<4) & 0x30);// 3E 3C
			
      LCD->RAM[LCD_RAMRegister_12] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_12] |= (uint8_t)(digit[3] & 0x03);// 3P1 3D
      break;
     
      /* Position 3 on LCD (Digit4)*/
    case 3:
      LCD->RAM[LCD_RAMRegister_1] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_1] |= (uint8_t)((digit[0]<<6) & 0xC0);// 4A 4B
			
      LCD->RAM[LCD_RAMRegister_5] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_5] |= (uint8_t)((digit[1]<<2) & 0x0C);// 4F 4G
			
      LCD->RAM[LCD_RAMRegister_8] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_8] |= (uint8_t)((digit[2]<<6) & 0xC0);// 4E 4C
			
      LCD->RAM[LCD_RAMRegister_12] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_12] |= (uint8_t)((digit[3]<<2) & 0x0C);// 4P1 4D
			
      break;
			
    default:
      break;
  }
}

/**
  * @brief  This function writes a char in the LCD RAM.
  * @param  ptr: Pointer to string to display on the LCD Glass.
  * @retval None
  */
void LCD_GLASS_DisplayString(uint8_t* ptr)
{
  uint8_t i = 0x00;
   
  /* Send the string character by character on lCD */
  while ((*ptr != 0) & (i < 8))
  {
    /* Display one character on LCD */
    LCD_GLASS_WriteChar(ptr, POINT_OFF, APOSTROPHE_OFF, i);
   
    /* Point on the next character */
    ptr++;
   
    /* Increment the character counter */
    i++;
  }
}

/**
  * @brief  This function Clear a char in the LCD frame buffer.
  * @param  position: position in the LCD of the chacter to write [0:7]
  * @retval None
  */
void LCD_GLASS_ClearChar(uint8_t position)
{
  switch (position)
  {
      /* Position 0 on LCD (Digit1)*/
    case 0:
      LCD->RAM[LCD_RAMRegister_1] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_4] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_8] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_11] &= 0xCF;
      break;
     
      /* Position 1 on LCD (Digit2)*/
    case 1:
      LCD->RAM[LCD_RAMRegister_1] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_4] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_8] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_11] &= 0x3F;
      break;
     
      /* Position 2 on LCD (Digit3)*/
    case 2:
      LCD->RAM[LCD_RAMRegister_1] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_5] &= 0xFC;
      LCD->RAM[LCD_RAMRegister_8] &= 0xCF;
      LCD->RAM[LCD_RAMRegister_12] &= 0xFC;
      break;
     
      /* Position 3 on LCD (Digit4)*/
    case 3:
      LCD->RAM[LCD_RAMRegister_1] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_5] &= 0xF3;
      LCD->RAM[LCD_RAMRegister_8] &= 0x3F;
      LCD->RAM[LCD_RAMRegister_12] &= 0xF3;
      break;
			
    default:
      break;
  }
}

/**
  * @brief  This function Clear the whole LCD RAM.
  * @param  None
  * @retval None
  */
void LCD_GLASS_Clear(void)
{
  uint8_t counter = 0;
  for (counter = 0;counter < 0x0C; counter++)
  {
    LCD->RAM[counter] =  LCD_RAM_RESET_VALUE;
  }
}

/**
  * @brief  Converts an ascii char to the a LCD digit (previous coding).
  * @param  c: a char to display.
  * @param  point: a point to add in front of char
  *         This parameter can be: POINT_OFF or POINT_ON
  * @param  apostrophe: flag indicating if a apostrophe has to be add in front
  *         of displayed character.
  *         This parameter can be: APOSTROPHE_OFF or APOSTROPHE_ON.
  * @retval None
  */
static void Convert(uint8_t* c, Point_Typedef point, Apostrophe_Typedef apostrophe)
{
  uint16_t ch = 0 , tmp = 0;
  uint8_t i;

  /* The character c is a letter in upper case*/
  if ((*c < 0x5B)&(*c > 0x40))
  {
    ch = LetterMap[*c-0x41];
  }
  /* The character c is a number*/
  if ((*c < 0x3A)&(*c > 0x2F))
  {
    ch = NumberMap[*c-0x30];
  }
  /* The character c is a space character */
  if (*c == 0x20)
  {
    ch = 0x00;
  }
  /* Set the DP seg in the character that can be displayed if the point is on */
  if (point == POINT_ON)
  {
    ch |= 0x0001;
  }

  /* Set the X seg in the character that can be displayed if the apostrophe is on */
  if (apostrophe == APOSTROPHE_ON)
  {
    ch |= 0x0001;
  }

  for (i = 0;i < 4; i++)
  {
    tmp = ch & mask[i];
    digit[i] = (uint8_t)(tmp >> (uint8_t)shift[i]);
  }
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
